#include "BuilderHelper.h"


BuilderHelper::BuilderHelper(float limInferior, float limSuperior) :
	m_limInferior(limInferior), m_limSuperior(limSuperior)
{
}


BuilderHelper::~BuilderHelper() { }


std::vector<glm::vec3> BuilderHelper::buildNormales(unsigned int cantPtsCurva, const std::vector<glm::vec3> &vecVertices) const {
	std::vector< glm::vec3 > vNomales;
	for (unsigned int i = 0; i < vecVertices.size(); ++i){
		// Usado para cambiar el orden del calculo de la normal
		bool revertirGiro = false;

		// Obtiene el siguiente punto en "X", cuidado si es el ultimo de la fila en la malla
		unsigned int posX1 = i +1;
		if (posX1 % cantPtsCurva == 0){
			posX1 = i -1;
			revertirGiro = !revertirGiro;
		}

		// Obtiene el proximo punto en "Y", cuidado si se esta en la ultima fila de la malla
		unsigned int posY1 = i + cantPtsCurva;
		if (posY1 >= vecVertices.size()){
			posY1 = i - cantPtsCurva;
			revertirGiro = !revertirGiro;
		}

		// Los puntos usados para calcular la normal
		glm::vec3 pt0 = vecVertices[i];
		glm::vec3 ptX1 = vecVertices[posX1];
		glm::vec3 ptY1 = vecVertices[posY1];

		glm::vec3 ptNormal = calcularNormal(pt0, ptX1, ptY1, revertirGiro);
		ptNormal = glm::normalize( ptNormal );
		vNomales.push_back( ptNormal );
	}

	return vNomales;
}


std::vector<glm::vec2> BuilderHelper::buildCoordsTextura(unsigned int cantHorizontal, unsigned int cantVertical) const {
	// Calculos previos
	const float intervalo = this->m_limSuperior - this->m_limInferior;
	const float tamPasoU = static_cast<float>( intervalo / (cantHorizontal -1) );
	const float tamPasoV = static_cast<float>( intervalo / (cantVertical -1) );

	// Construye las corrdenadas
	std::vector< glm::vec2 > vTemp;

	for (unsigned int j = 0; j < cantVertical; ++j){
		for (unsigned int i = 0; i < cantHorizontal; ++i){
			const float u = this->m_limInferior + i * tamPasoU;
			const float v = this->m_limInferior + j * tamPasoV;

			vTemp.push_back( glm::vec2(u, v) );
		}
	}

	return vTemp;
}


std::vector<unsigned int> BuilderHelper::buildIndexBuffer(unsigned int cantHorizontal, unsigned int cantVertical) const {
	// Construye el indexBuffer
	std::vector<unsigned int> vIndices;

	// Construye la superficie abierta
	for (unsigned int j = 0; j < cantVertical-1; ++j){
		for (unsigned int i = 0; i < cantHorizontal-1; ++i){
			// No es muy lindo el algoritmo pero deberia funcionar
			unsigned int saltoJ = j * cantHorizontal;

			unsigned int a1 = i + saltoJ;
			unsigned int b1 = (i +1) + saltoJ;
			unsigned int c1 = (i + cantHorizontal) + saltoJ;

			unsigned int a2 = (i +1) + saltoJ;
			unsigned int b2 = (i +1) + cantHorizontal + saltoJ;
			unsigned int c2 = (i + cantHorizontal) + saltoJ;

			vIndices.push_back( a1 );
			vIndices.push_back( b1 );
			vIndices.push_back( c1 );

			vIndices.push_back( a2 );
			vIndices.push_back( b2 );
			vIndices.push_back( c2 );
		}
	}

	return vIndices;
}


// Usa metodos numericos para aproximar la normal en un punto
glm::vec3 BuilderHelper::calcularNormal(glm::vec3 punto0, glm::vec3 puntoX, glm::vec3 puntoY, bool revertir) const {
	// (X - X0) ^ (X - Y0)
	glm::vec3 ptX = puntoX - punto0;
	glm::vec3 ptY = puntoY - punto0;

	if (revertir) return glm::cross( ptX, ptY );
	else return glm::cross( ptY, ptX );
}

